#pragma once

#include "log.hpp"
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define gbacklog 5

using namespace std;

enum
{
    USAGE_ERR = 1,
    SOCK_ERR,
    BIND_ERR,
    LISTEN_ERR,
    READ_ERR
};

class Server
{
public:
    Server(const uint16_t &port)
        : _listenSock(-1), _port(port)
    {
    }

    void initServer()
    {
        // 1.创建套接字
        _listenSock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listenSock < 0)
        {
            logMessage(FATAL, "监听套接字创建失败");
            exit(SOCK_ERR);
        }
        logMessage(NORMAL, "创建套接字成功");

        // 2.绑定端口号
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = htonl(INADDR_ANY);
        int n = bind(_listenSock, (struct sockaddr *)&local, sizeof(local));
        if (n == -1)
        {
            logMessage(FATAL, "绑定端口号失败");
            exit(BIND_ERR);
        }
        logMessage(NORMAL, "绑定端口号成功");

        // 3.设置监听状态
        n = listen(_listenSock, gbacklog);
        if (n < 0)
        {
            logMessage(FATAL, "监听设置失败");
            exit(LISTEN_ERR);
        }
        logMessage(NORMAL, "监听设置成功");
    }

    void serverIO(int sock)
    {
        char buf[1024];
        while (1)
        {
            int n = read(sock, buf, sizeof(buf) - 1);
            if (n < 0)
            {
                logMessage(FATAL, "服务端读取错误");
                exit(READ_ERR);
            }
            else if (n == 0)
            {
                cout << "客户端退出，我也退出" << endl;
                break;  
            }
            else
            {
                buf[n] = 0;
                cout << "客户端# " << buf << endl;

                string responce = buf;
                responce += " 服务端返回";
                write(sock, responce.c_str(), responce.size());
            }
        }
    }

    void start()
    {
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        while (1)
        {
            // 4.接收连接请求，建立连接
            int sock = accept(_listenSock, (struct sockaddr *)&client, &len);
            if (sock < 0)
            {
                logMessage(ERROR, "接收失败"); // 几首失败 不退出，继续重新接收
                continue;
            }
            logMessage(NORMAL, "链接成功");

            // 5.收发数据，TCP面向字节流，读写数据和文件操作一样
            //目前获取链接和收发数据是串行的
            serverIO(sock);
            close(sock);    //数据收发完毕后关闭文件描述符，否则易造成文件描述符泄露
        }
    }

    ~Server()
    {
    }

private:
    int _listenSock;
    uint16_t _port;
};
